#include <fstream>   // file stream : ifstream & ofstream
#include <iostream> 
#include <string.h>
#include <sstream>   // string stream
#include <vector>
// #include <bits/stdc++.h>

// 1. 从文件中读取数据

void ifstream_read(std::string& file, std::ios_base::openmode openmode) {
    // call construct func
    std::ifstream fin(file, openmode);
    if (!fin.is_open()) {   // if (fin.is_open() == false)
        std::cerr << "File open error!" << std::endl;
        return;
    }
    std::string val;                        //! 默认会识别空格与换行，数字转为string
    // int   val;                           //! 非数值类型值不识别, 浮点为int
    // float val;                           //! 数值类型均ok
    // while (fin >> val) {                  
    // 	std::cout << val << ": " << std::stoi(s_base::ival, 0, 10) << std::endl;
    //     std::cout << std::stof(val)  << std::endl;   // namespace std
        // std::to_string(int, float, double)


        //! v1: C语言风格, #include <stdlib.h>，不进行错误检查, 输入无效时返回0且没有错误信息
        // atoi(val.c_str());

        //! v2: C++风格， #include <string>, 输入无效时会抛出异常，可处理多种进制
        // int stoi(const std::string& str, std::size_t* pos = 0, int base = 10);
        // std::stoi(val, nullptr, 10);
    // }

    //////////////////////////////////////////////////////////////
    //! 使用fin.getline()
    // const int LINE_MAX = 100;
    // char  str[LINE_MAX];
    // int line_cout = 0;s_base::i
    // //! 必须是char[], 不能是string
    // // 空格保留, 按换行符区别, 如果一行有多个数据，则需要自己去切分
    // // while (fin.getlinsic_ie(str, LINE_MAX)) {       
    // //     std::cout << str << std::endl;
    // //     line_cout++;
    // // }

    // // 空格保留, 按换行符区别, 如果一行有多个数据，则需要自己去切分
    // //! 使用sstream对行数据进行处理
    // std::vector<std::vector<int>> matrix;
    int line_cout = 0;  // fin
    while (std::getline(std::cin, val)) {      // val = "";    
        // std::cout << val << std::endl;
        // std::istringstd::getline(fin, val)ream iss(val);
        std::istringstream iss(val);   // call constructor
        // std::vector<int> row;
        // line_cout++;

        int item;
        while (iss >> item) {
            // row.emplace_back(item);
            std::cout << item << " ";
        }
        std::cout << std::endl;
        // matrix.push_back(row);
        // line_cout++;
        // std::cout << "line cout: " << line_cout << ", " << val << std::endl;
    }
   

    fin.close();  // close the file
}

// 2. 写入数据到文件
void ofstream_write(std::string& file, std::ios_base::openmode openmode) {
    //! 参考其构造函数
    // v1: basic_ofstream(const char* __s, ios_base::openmode __mode = ios_base::out)
    // v2: basic_ofstream(const std::string& __s, ios_base::openmode __mode = ios_base::out)
    
    //! 成员方法
    // 1. void open(const char* __s, ios_base::openmode __mode = ios_base::out)
    // 2. void open(const std::string& __s, ios_base::openmode __mode = ios_base::out)
    // 3. void close()
    // 4. bool is_open()

    //! openmode
    /**
     * @brief openmode
     *   - ios_base::app     
     *      - 追加模式。所有写入都追加到文件末尾，文件指针始终在文件末尾，不允许用户移动
     *      - 当这个标志被设置时，即使使用了 seekp（设置写指针位置）函数，所有写入操作也总是发生在文件末尾。
     *   - ios_base::ate
     *      - 打开文件时立即定位到文件末尾。
     *      - 不同于 ios::app，在这种模式下，你可以改变文件内的位置并写入任意位置。
     *   - ios_base::binary
     *      - 以二进制模式打开文件。
     *      - 在这种模式下，文件不会对换行符 \n 或任何特定字符进行特殊处理。
     *   - ios_base::in
     *      - 以读取模式打开文件，文件必须存在
     *      - 用于 ifstream，可以单独使用，也可以与其他模式结合使用（如 ios::in | ios::binary）。
     *   - ios_base::out
     *      - 以写入模式打开文件，文件不存在则创建
     *      - 用于 ofstream，可以单独使用，也可以与其他模式结合使用。
     *   - ios_base::trunc
     *      - 如果文件已存在，首先将其长度截断为 0，然后打开文件。
     *      - 这个标志常用于与 ios::out 模式结合使用，确保打开文件时文件内容被清空。
     * @return std::ofstream 
     */
    int len = 8;
    int iArray[] = {23, 45, 57, 68, 23, 46, 68, 34};

    // std::ofstream ofs("vector.txt", std::ios::app);
    // std::ofstream ofs("vector.txt", std::ios::ate | std::ios::in);
    //! std::ios::ate | std::ios::in == std::ios::app
    std::ofstream ofs(file, openmode);
    if (!ofs) {             // if (!ofs.is_open())   if (ofs.is_open() == false)
        std::cerr << "File open error!" << std::endl;
        exit(1);
    }

    // （1）使用重载形式输入int型数据到文件中
    for (size_t i = 0; i < len; i++) {
        ofs << iArray[i] << " ";
        if ((i+1)%4 == 0)
            ofs << std::endl;
    }
    // ofs << std::endl;
 
    // （2）使用ofstream成员函数write()写入文件中
    // ofs.write("ZhuHai", strlen("ZhuHai"));
    ofs.close();          // 关闭输出文件流
}

int main(int argc, const char** argv) {
    std::string  txt_file = "vector.txt";
    ifstream_read(txt_file, std::ios_base::in);  // read only
    // ofstream_write(txt_file, std::ios_base::out);
    
    return 0;
}